package ru.spb.osll.myfit.server.services;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.apache.log4j.Logger;
import ru.spb.osll.myfit.common.PageElement;
import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.server.Configurator;
import ru.spb.osll.myfit.server.Converter;
import ru.spb.osll.myfit.server.FixtureNameComparator;
import ru.spb.osll.myfit.server.MyFitClassLoaderFactory;
import ru.spb.osll.myfit.server.fixtureiterator.FileFactory;
import ru.spb.osll.myfit.server.handler.*;
import ru.spb.osll.myfit.server.parser.TableUtils;
import ru.spb.osll.myfit.server.templateloader.JarTableTemplateLoader;
import ru.spb.osll.myfit.server.templateloader.TableTemplateLoader;
import ru.spb.osll.myfit.util.StringUtils;

import java.lang.reflect.Method;
import java.net.URLClassLoader;
import java.util.*;

@SuppressWarnings("serial")
public class CreateHelperServiceImpl extends RemoteServiceServlet implements
        ru.spb.osll.myfit.client.service.CreateHelperService {
  private static Logger log = Logger.getLogger(CreateHelperServiceImpl.class);

  private Converter m_converter = new Converter();
  private TableTemplateLoader m_templateLoader;
  private TreeMap<String, String> m_templates;
  private PageNamesLoader m_pageNamesLoader;
  private Handler m_contentHandler;
  private Map<String, Class<?>> m_fixtureClasses;
  private Configurator m_configurator;

  public CreateHelperServiceImpl() {
    initialize();
  }

  private synchronized void initialize() {
    m_configurator = Configurator.getInstance();
    URLClassLoader m_classLoader = new MyFitClassLoaderFactory(
            new FileFactory()).createClassLoader(m_configurator.getDependenciesDir(),
            m_configurator.getFixtureDir());
    m_templateLoader = new JarTableTemplateLoader(
            m_configurator.getFixtureDir(), m_classLoader);
    m_fixtureClasses = m_templateLoader.getFixtureClasses();
    m_templates = new TreeMap<String, String>(new FixtureNameComparator());
    for (Map.Entry<String, Class<?>> entry : m_fixtureClasses.entrySet()) {
      Class<?> clazz = entry.getValue();
      try {
        Method getTestTableTemplatesMethod = clazz.getMethod("getTestTableTemplates");
        String[] templates = (String[]) getTestTableTemplatesMethod.invoke(null);
        boolean templatesCorrect = true;
        if (templates != null) {
          String concat = "";
          for (String s : templates) {
            if (s != null) {
              concat += s;
            } else {
              templatesCorrect = false;
              break;
            }
          }
          if (concat.equals("")) {
            templatesCorrect = false;
          }
        } else {
          templatesCorrect = false;
        }
        if (templatesCorrect) {
          m_templates.put(StringUtils.splitCamelCase(clazz.getSimpleName()), entry.getKey());
        } else {
          log.warn("\"getTestTableTemplates\" method of fixture" + clazz.getName() + " returned empty or null value. " +
                  "Won't be added to list of available fixtures");
        }
      } catch (Exception e) {
        log.warn("Invoking \"getTestTableTemplates\" method for fixture " + clazz.getName() + " failed. " +
                "Won't be added to list of available fixtures");
      }

    }

    PageLoader pageLoader = new PageLoader(new TableUtils(m_fixtureClasses));
    m_contentHandler = new ContentHandler(m_configurator.getRootDir(),
            pageLoader, new ContentCreator(), new ParentVariablesCreator(
            pageLoader));

    m_pageNamesLoader = new PageNamesLoader();
  }

  @Override
  public TreeMap<String, String> loadTemplates() throws Exception {
    initialize();
    TreeMap<String, String> map = new TreeMap<String, String>();
    map.putAll(m_templates);
    return map;
  }

  @Override
  public Table getTemplate(String name) throws Exception {
    Class<?> clazz = m_fixtureClasses.get(name);
    Vector<String> rawTable = m_templateLoader.getTemplate(clazz.getName());
    Table table = m_contentHandler.getTable(rawTable,
            TableUtils.getTableStyle(clazz));
    return table;
  }

  public String convertWikiToHtml(String wikiText) {
    return m_converter.convertWikiToHtml(wikiText);
  }

  public PageElement loadInclude(String pagePath, String includePath) {
    return m_contentHandler.loadInclude(includePath, pagePath);
  }

  @Override
  public PageElement createContent(int level, String pagePath) {
    return m_contentHandler.createContent(m_configurator.getRootDir(), pagePath,
            level);
  }

  @Override
  public List<String> loadPageNames() {
    List<String> pageNames = m_pageNamesLoader.loadNames(m_configurator.getRootDir());
    return new LinkedList<String>(pageNames);
  }
}
